package com.doge.calcalbum.utils

import android.content.Context
import android.os.Build
import android.os.Handler
import android.os.LocaleList
import android.os.Looper
import android.util.Log
import android.view.animation.AnimationUtils
import androidx.core.content.edit
import com.doge.calcalbum.App
import com.doge.calcalbum.BuildConfig
import com.doge.calcalbum.R
import com.doge.calcalbum.api.workScheduler
import com.doge.calcalbum.db.CalcDB
import com.google.gson.Gson
import io.reactivex.Observable
import io.reactivex.schedulers.Schedulers
import java.io.Closeable
import java.lang.reflect.Type
import java.text.NumberFormat
import java.text.SimpleDateFormat
import java.util.*

val appContext: Context get() = App.context
val db: CalcDB get() = CalcDB.getInstance(appContext)
val mainHandler by lazy { Handler(Looper.getMainLooper()) }

fun isMainThread() = Looper.getMainLooper() == Looper.myLooper()
fun runOnUI(block: () -> Unit) {
    if (Looper.getMainLooper() == Looper.myLooper()) {
        block()
    } else {
        mainHandler.post(block)
    }
}

fun runOnIO(block: () -> Unit) {
    Observable.fromCallable(block).subscribeOn(Schedulers.io())
        .subscribe()
}

fun runOnWork(block: () -> Unit) {
    Observable.fromCallable(block).subscribeOn(workScheduler)
        .subscribe()
}

fun runInTransaction(block: () -> Unit) = runOnWork {
    db.runInTransaction(block)
}


fun log(msg: String?, tag: String = "appCalc") {
    if (msg?.isNotEmpty() == true && BuildConfig.DEBUG) Log.i(tag, msg)
}

fun logE(msg: String?, tag: String = "appCalc") {
    if (msg?.isNotEmpty() == true && BuildConfig.DEBUG) Log.e(tag, msg)
}

fun spWrite(key: String, value: Any?, folder: String) {
    log("spWrite folder $folder key $key value $value")
    appContext.getSharedPreferences(folder, Context.MODE_PRIVATE)
        .edit {
            when (value) {
                null -> putString(key, null)
                is String -> putString(key, value)
                is Int -> putInt(key, value)
                is Boolean -> putBoolean(key, value)
                is Long -> putLong(key, value)
                is Float -> putFloat(key, value)
                else -> throw IllegalArgumentException("not support value $value")
            }
        }
}

fun spReadInt(key: String, defaultValue: Int = 0, folder: String): Int {
    return appContext.getSharedPreferences(folder, Context.MODE_PRIVATE)
        .getInt(key, defaultValue).also {
            log("spReadInt folder $folder key $key value $it")
        }
}

fun spReadLong(key: String, defaultValue: Long = 0, folder: String): Long {
    return appContext.getSharedPreferences(folder, Context.MODE_PRIVATE)
        .getLong(key, defaultValue).also {
            log("spReadInt folder $folder key $key value $it")
        }
}

fun spReadBoolean(key: String, defaultValue: Boolean = true, folder: String): Boolean {
    return appContext.getSharedPreferences(folder, Context.MODE_PRIVATE)
        .getBoolean(key, defaultValue).also {
            log("spReadBoolean folder $folder key $key value $it")
        }
}

fun spReadString(
    key: String,
    defaultValue: String?,
    folder: String
): String? {
    return appContext.getSharedPreferences(folder, Context.MODE_PRIVATE)
        .getString(key, defaultValue).also {
            log("spReadString folder $folder key $key value $it")
        }
}

val gson = Gson()

// 将json字符串转化为指定对象类型
fun <T> fromJson(json: String?, classOfT: Class<T>): T? {
    if (json == null) return null
    return try {
        gson.fromJson(json, classOfT)
    } catch (e: Exception) {
        log("fromJson error $json")
        null
    }
}

fun <T> fromJson(json: String?, typeOfT: Type): T? {
    if (json == null) return null
    return try {
        gson.fromJson(json, typeOfT)
    } catch (e: Exception) {
        log("fromJson error $json")
        null
    }
}

// 将对象转化为json字符串
fun toJson(src: Any?): String {
    if (src == null) return ""
    return gson.toJson(src)
}

fun closeQuietly(stream: Closeable?) {
    try {
        stream?.close()
    } catch (ignored: java.lang.Exception) {
    }
}

fun Long?.timeDesc(format: String = "yyyy年MM月dd日"): String {
    if (this == null) return ""
    return SimpleDateFormat(format).format(Date(this))
}

val language: Locale by lazy {
    (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        LocaleList.getDefault().get(0)
    } else {
        Locale.getDefault()
    })
}

val String?.md5: String?
    get() {
        if (this.isNullOrEmpty()) return null
        return MD5Utils.getMD5String(this.trim { it <= ' ' }.uppercase(Locale.ROOT))
    }

val Float?.percentage: String
    get() {
        if (this == null) return ""
        // https://blog.csdn.net/jlq_diligence/article/details/103955965
        val fmt = NumberFormat.getPercentInstance()
        fmt.maximumFractionDigits = 2// 最多两位百分小数，如25.23%
        return fmt.format(this)
    }


fun Int?.isNullOrZero() = this == null || this == 0
fun Long?.isNullOrZero() = this == null || this == 0L
